package com.jzo2o.foundations.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeItem;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.*;
import com.jzo2o.foundations.service.IRegionServeService;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: liZhiJun
 * @CreateTime: 2025-09-24
 * @Description: 区域服务实现
 * @Version: 1.0
 */

@Service
@RequiredArgsConstructor
@Slf4j
public class RegionServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IRegionServeService {
    private final ServeMapper serveMapper;
    private final IRegionService regionService;
    private final RabbitTemplate rabbitTemplate;
    @Autowired
    private IServeItemService serveItemService;
    //上架
    public static final Integer ON_SALE = 2;
    //下架
    public static final Integer OFF_SALE = 1;
    //草稿
    public static final Integer DRAFT = 0;
    //热门
    public static final Integer HOT = 1;
    //非热门
    public static final Integer NON_HOT = 0;
    //服务项启用
    public static final Integer ITEM_ON = 2;


    /**
     * 服务分页查询
     *
     * @param servePageQueryReqDTO
     * @return
     */
    @Override
    public Page<ServeResDTO> page(ServePageQueryReqDTO servePageQueryReqDTO) {
        Page<ServeResDTO> page = new Page<>(servePageQueryReqDTO.getPageNo(), servePageQueryReqDTO.getPageSize());
        return serveMapper.page(page, servePageQueryReqDTO.getRegionId());
    }

    /**
     * 服务批量新增
     *
     * @param serveUpsertReqDTOS
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#serveUpsertReqDTOS[0].regionId")
    public void batchSava(List<ServeUpsertReqDTO> serveUpsertReqDTOS) {
        //参数校验
        if (CollectionUtils.isEmpty(serveUpsertReqDTOS)) {
            throw new RuntimeException("参数错误,不能为空");
        }
        if (serveUpsertReqDTOS.get(0).getRegionId() == null) {
            throw new RuntimeException("参数错误,区域id不能为空");
        }
        Region region = regionService.getById(serveUpsertReqDTOS.get(0).getRegionId());
        if (region == null) {
            throw new RuntimeException("区域不存在");
        }
        //查询区域是有存在该服务项
        List<Serve> serveList = serveMapper.selectList(Wrappers.<Serve>lambdaQuery().eq(Serve::getRegionId, region.getId())
                .in(Serve::getServeItemId, serveUpsertReqDTOS.stream().map(ServeUpsertReqDTO::getServeItemId).collect(Collectors.toList())));
        if (!CollectionUtils.isEmpty(serveList)) {
            throw new ForbiddenOperationException("有服务项该区域已存在" + serveList.toString());
        }
        //查询服务项 状态
        List<ServeItem> serveItemList = serveItemService.list(Wrappers.<ServeItem>lambdaQuery()
                .ne(ServeItem::getActiveStatus, ITEM_ON)
                .in(ServeItem::getId,
                        serveUpsertReqDTOS.stream().map(ServeUpsertReqDTO::getServeItemId).collect(Collectors.toList())));
        if (!CollectionUtils.isEmpty(serveItemList)) {
            throw new ForbiddenOperationException("有服务项未启用" + serveItemList.toString());
        }


        //组装参数
        ArrayList<Serve> serves = new ArrayList<>();
        for (ServeUpsertReqDTO serveUpsertReqDTO : serveUpsertReqDTOS) {
            Serve serve = new Serve();
            serve.setRegionId(serveUpsertReqDTO.getRegionId());
            serve.setServeItemId(serveUpsertReqDTO.getServeItemId());
            serve.setPrice(serveUpsertReqDTO.getPrice());
            serve.setSaleStatus(DRAFT);
            serve.setIsHot(NON_HOT);
            serve.setCityCode(region.getCityCode());
            serves.add(serve);
        }
        super.saveBatch(serves);
    }

    /**
     * 修改价格
     *
     * @param id
     * @param price
     */
    @Override
    public void updatePrice(Long id, BigDecimal price) {
        if (id == null || price == null) {
            throw new RuntimeException("参数错误,不能为空");
        }
        super.updateById(new Serve().setId(id).setPrice(price));
        //发送消息
        try {
            rabbitTemplate.convertAndSend("serve.exchange", "serve.updatePrice", id + "");
            log.info("rabbitmq发送修改成功{}", id);

        } catch (AmqpException e) {
            log.error("rabbitmq发送修改失败,服务批量新增失败", e);
        }

    }

    /**
     * 上架
     *
     * @param id
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, allEntries = true),
            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, allEntries = true),
            @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)
    })
    public void onSale(Long id) {
        Serve serve = extracted(id);
        //判断服务项是否启用或存在
        ServeItem serveItem = serveItemService.getOne(Wrappers.<ServeItem>lambdaQuery()
                .eq(ServeItem::getId, serve.getServeItemId())
                .eq(ServeItem::getActiveStatus, ITEM_ON));
        if (serveItem == null) {
            throw new RuntimeException("服务项不存在或没有启用");
        }
        super.updateById(new Serve().setId(id).setSaleStatus(ON_SALE));
        //发送消息
        try {
            rabbitTemplate.convertAndSend("serve.exchange", "serve.onSale", id + "");
            log.info("rabbitmq发送成功{}", id);

        } catch (AmqpException e) {
            log.error("rabbitmq发送失败,服务批量新增失败", e);
        }
    }

    /**
     * 参数校验
     *
     * @param id
     */
    private Serve extracted(Long id) {
        if (id == null) {
            throw new RuntimeException("参数错误,不能为空");
        }
        Serve serve = super.getById(id);
        if (serve == null) {
            throw new RuntimeException("服务不存在");
        }
        return serve;
    }

    /**
     * 下架
     *
     * @param id
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, allEntries = true),
            @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, allEntries = true),
            @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)
    })
    public void offSale(Long id) {
        extracted(id);
        super.updateById(new Serve().setId(id).setSaleStatus(OFF_SALE));
        try {
            rabbitTemplate.convertAndSend("serve.exchange", "serve.offSale", id + "");
            log.info("rabbitmq,服务下架发送成功{}", id);
        } catch (AmqpException e) {
            log.error("rabbitmq，下架发送失败,服务批量新增失败", e);
        }
    }

    /**
     * 设置热门
     *
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)
    public void onHot(Long id) {
        extracted(id);
        super.updateById(new Serve().setId(id).setIsHot(HOT));
    }

    /**
     * 取消热门
     *
     * @param id
     */
    @Override
    @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, allEntries = true)
    public void offHot(Long id) {
        extracted(id);
        super.updateById(new Serve().setId(id).setIsHot(NON_HOT));
        //发送消息
    }

    /**
     * 首页服务列表
     *
     * @param regionId 区域id
     * @return 首页服务列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", cacheManager = RedisConstants.CacheManager.ONE_DAY)
    public List<ServeCategoryResDTO> firstPageServeList(Long regionId) {
        List<ServeCategoryResDTO> serveCategoryResDTOS = serveMapper.firstPageServeList(regionId);
        //判断数量是否大于二
        int size = Math.min(serveCategoryResDTOS.size(), 2);
        List<ServeCategoryResDTO> limitServeCategoryResDTOS = serveCategoryResDTOS.stream().limit(size).collect(Collectors.toList());
        for (ServeCategoryResDTO dto : limitServeCategoryResDTOS) {
            //判断数量是否大于4
            size = Math.min(dto.getServeResDTOList().size(), 4);
            List<ServeSimpleResDTO> simpleResDTOS = dto.getServeResDTOList().stream().limit(size).collect(Collectors.toList());
            dto.setServeResDTOList(simpleResDTOS);
        }
        return limitServeCategoryResDTOS;
    }

    /**
     * 热门服务列表
     *
     * @param regionId 区域id
     * @return 热门服务列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES)
    public List<ServeAggregationSimpleResDTO> hotServeList(Long regionId) {
        return serveMapper.hotServeList(regionId);
    }

    /**
     * 服务类型列表
     *
     * @param regionId 区域id
     * @return 服务类型列表
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", cacheManager = RedisConstants.CacheManager.FOREVER)
    public List<ServeAggregationTypeSimpleResDTO> serveTypeList(Long regionId) {
        return serveMapper.serveTypeList(regionId);
    }

    /**
     * 服务详情
     *
     * @param id
     * @return
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
    public ServeAggregationSimpleResDTO getServeDetailById(Long id) {
        return serveMapper.getServeDetailById(id);
    }

    @Override
    public ServeAggregationResDTO getServeForOrderById(Long id) {
        return serveMapper.getServeForOrderById(id);
    }

}
